import 'dart:convert';

/*
课后作业：
对比Js和Dart数据类型,区别
Js是弱类型语言 Dart是强类型的语言（同时支持一些弱类型语言） Dart弱类型有var，Object，dynamic
  （ var 初始化确定类型后不可更改类型， Object 以及dynamic 可以更改类型，Object 编译阶段检查类型, 而 dynamic 编译阶段不检查类型）
声明变量
1，var关键字
dart和js都支持
2，final关键字Dart中使用
3，默认值
  Js中变量的初始值是undefined ，Dart未初始化变量默认值是null（用final的话必须定义初始值）
4，类型判断
  JS用typeof判断基本类型（字符串String，数值Number，布尔值Boolean，undefined），用instanceof潘丹引用类型（Object，Array，Function）
  Dart用关键字is进行类型判断，返回布尔,assert生成环境忽略，debug模式开启
  (var a=1;  print(a is dynamic); assert(a is Object))
5，类型转换
  Js除了自动抓换之外，还有类型转换方法
  （Json和字符串相互转换 var str=JSON.string(obj)，JSON.parse(str)。Number('2'),parseInt('2.2')...）
  Dart通过Dart:convert中内置的内置的JSON解码器json.decode()进行转换
6，布尔值
  Js：自动类型转化，空字符串，0，null，undefined 都为FALSE（var flag=1=='1' 输出 TRUE）
  Dart：强制类型语言 不自动类型转换
7,字符串
  Js：字符串拼接使用加号+，反引号`str${变量名称}`，获取长度length，返回给定位位置的字符str.charAt(1),拼接concat，截取slice(0,1),substr(0,1),substring(2)后两位，
      'str'.indexOf('s')校验是否存在不存在返回-1，lastIndexOf('t')末尾开始查找，trim()删除前后空格，toLowerCase()转小写，toUpperCase()转大写，
      toLocaleLowerCase()，toLocaleUpperCase()大小写针对地区写法
      str.match('s')//["s", index: 0, input: "string", groups: undefined]
      str.search('s') 返回字符串中第一个匹配项的索引，没有返回-1
      str.replace('s','c')替换，split()分割字符串返回数组
  Dart：使用前缀 r 创建 raw string，字符串内不会进行转义String str = r'haha \n breakLine' // 不换行，输出haha \n breakLine
      拼接'$str 111'或'${str} 111',获取长度length，判断为空isEmpty;是否不为空isNotEmpty,assert(str.substring(0, 2))字符串切割,
      substring(3)从指定index至末尾,字符串分隔split，
      字符串判断：assert(str.startsWith('a'))以a开始返回布尔值，satrtsWith('a',2)从index=2判断，endsWith('c')以c结尾，contaiins('c')是否包含，
      contains('a',2)从index=2开始判断
      字符串替换：replaceAll("st","cc")替换所有符合的，replaceFirst("ing", "ss")只替换第一个符合的，replaceFirst("ing", "dd",5)从index=5替换第一个符合的，
      replaceRange(0, 3, "z")范围替换0-3含0不含3，replaceAllMapped用方法返回值替换指定的字符串,
      replaceFirstMapped("i",(Match match){return 1},5)从index=5开始 用方法返回值替换指定的字符串,
      indexOf()从前往后找返回第一个符合的index，lastIndexOf('1')从后往前找返回第一个符合的索引，toLowerCase()转小写，toUpperCase()转大写，
      trim()去除左右空格，trimLeft()去除左边空格，trimRight()去除右边空格，
      补齐长度：var s=111,padLeft(6)剩余三位自动补齐，padRight(6,'2')111222剩余三位指定2，padLeft(2,'a')若指定长度原字符长度 返回原来的字符串
8，对象
  Js：Object.keys(obj)返回对象的key组成的数组，Object.values(obj)返回对象的value组成的数组，Object.assgin()可以将源对象复制到目标对象，
      obj.hasOwnProperty()判断对象中属性是否存在
  Dart:var obj={'name':'7878'};var obj=Map();obj['name']='7878'
9，数组
  Js：concat()连接两个新数组，arr.every(i=>i>3)检测数值元素 的每个元素是否都符合条件返回布尔值，arr.some(i=>i>3)检测是否有符合条件的值，
      arr.filter(i=>i>3)检测数值元素返回条件符合所有元素数组，arr.find(i=>i=3)返回符合传入测试（函数）条件的数组元素，forEach遍历数组，
      arr.join('')把数组所有元素放入字符串，arr.map(i=>i+1)通过指定函数处理数组每个元素并返回处理之后的数组，pop()删除最后一个元素返回删除的元素，push()末尾追加一个元素，
      shift()删除并返回数组的第一个元素，sort()排序，toString()把数组转化字符串逗号隔开，unshift()首位添加一个元素，arr.reduce((curr,next)=>curr+next)数组相加的总和
  Dart：同Js部分，forEach遍历数组，map，sort排序，every，reduce
        fold用法同reduce，arr.contains(1)是否包含某个元素，arr.where((i)=>i>1)返回满足条件元素集合数组，firstWhere返回满足条件的第一个元素单个元素，
        arr.singleWhere((i)=>i>2,orElse:()=>null)返回数组满足给定条件的唯一一个元素单个元素若多个抛出异常，
        arr.take(2).toList()从数组取前n个元素，skip跳过数组的前n个元素，arr.from(arr1)克隆一个数组，
        expand:var arr1 = [[2, 5], [7], [11, 12]];arr1.expand((i)=>i).toList();返回[2, 5, 7, 11, 12]
        对每一项进行计算时类似map(),arr.map((i)=>i*8).toList();arr.add(1)像数组添加元素;addAll([1,2])像数组添加另一个数组所有元素

个人练习：
定义变量
Dart 变量：明确声明Explicit  变量类型 变量名称=变量值   明确声明之后的变量不可以被其他类型的变量赋值
  dart是一个强大的脚本类语言，可以不预先定义变量类型自动会类型推导
  dart中定义变量可以通过var关键字 可以通过类型来申明变量
  如：
  var str='this is var';
  String ste='this is var';
  int str=123;
  注意 var 和类型 不同时存在
  类型推导
  var/dynamic/const/final 变量名称=变量值
  var 在使用时会直接取当前赋值的变量类型 获取之后就确定下来了 不可以在使用其它类型给该变量赋值  var  name="999"  name=11 错误
  dynamic 动态确定变量类型 不建议该写法 容易出现类型安全问题
  例如：dynamic name="jack"; name=18

Dart 常量：final和const 修饰符 在获得了确定值之后不可以被修改
  const值不变 一开始就得赋值
  final可以开始不赋值  只赋值一次
  final是运行时动态获取的一个常量值 const是在编译期间就确定下来的常量值
  const name="阿" const date=DateTime.now() 错误使用  final date=DateTime.now() 正确
  :name的复制是在编译的时候就给定了确定的字符串 是正确的  final可以在运行时给定的一个常量  final和cons赋值之后都不可以再被改变
  final name='oshaj'; final String name='jak';
  const br=1000;  const doubel atm=1.00
Dart的命名规则：
  1，变量名字必须由数字 字母  下划线和美元符$组成
  2，注意：标示符开头不能是数字 禁止 var  2str=...
  3，标示符不能保留字和关键字  禁止 var  if=...
  4，变量名字区分大大小写：如 age和Age是不同的变量 （所以建议不要用一个单词大小写区分两个变量）
  5，标示符（变量名称）一定要见名思意：变量名称建议用名字 方法名字建议用动词

数据类型
1，数字类型 int double   2，布尔类型 bool
3，字符串类型 String  String name="09090" if(name){}错误写法 Dart中不可以使用非空即真用法
4，集合  Dart有三种聚合类型List/Set/Map
    List List =['a'];这种方式是推导List的数据类型
    List<int> intList=[1,2,3]; 知道List的数据类型 list.add(xxx); list.remove(xxx);list.removeAt(index)// 根据下标删除
    Set  set={'a','d'} 这种方式是推导Set的数据类型
    Set<int> intSet={1,2} 知道Set的数据类型为int set.add(xxx); set.remove(xxx);
    Map map={'name':'小妮'};这种方式是推导Map的数据类型 map['name']根据key获取值
    Map<String,String> typeMap={'name':'小妮'};指定Map数据类型
      print('${map.entries}'); 获取所有内容
      print('${map.keys}'); 获取所有key
      print('${map.values}'); 获取所有key
      map.containKey('xxx');  true || false  判断是否包含某个key
      map.remove('xxx');根据key删除元素
5，函数    类型是Function
   函数的定义： 返回值  函数名称（参数列表）{函数体 return  返回值}
   完整的函数定义  int sum(num num1,num  num2){ return num1+num2}
   箭头函数 内容不能是语句 只能是一个表达式
   sum(num num1,num  num2)=>num1*num2
   参数：两种类型 ：可选参数  必选参数
   可选：命名可选参数
   funcName({int age,double height}){}
   调用 命名可选参数调用不区分顺序 funcName() funcName(age:1) funcName(age:1,height:9.0)
   funcName([int age,double height]){}
   调用 位置可选参数时必须按照声明时的顺序传参funcName() funcName(1) funcName(1,9.0)
   必选：
   命名必选参数
   funcName(String name) funcName('jack')
   参数默认值：可选参数才有默认值  必选没有
   匿名函数 funcName(a){print(a)}
 */
//主函数（入口函数）
main() {
  // var str='Hello Dart';
  // var num=1234;
  //字符串
  String str = 'Hello Dart ~';
  //數字類型
  int num = 124;
  //dart 里面有类型校验 出现错误提示
  // var str='';
  // str=1233;
  // List list=[1,3,4,6];
  // list.removeAt(1);
  // Map map={'num':1,'m':98989};
  // Set set={'name','jk'};
  // set.remove('jk2');
  // print('${map.entries}');
  // list.forEach((element) {
  //     print(element);
  // });
  // print(map.remove('num'));

  //类型转换
  String jsonStr = '[{"name":"Jack"},{"name":"Rose"}]';
  List list = json.decode(jsonStr);
  print(list[0]['name']);
  // 布尔值
  // bool flag = 1 == '1';
  // print(flag);
  // 检查是否为空字符串
  // var fName = '';
  // print(fName.isEmpty);
  // assert(fName.isEmpty);
// 检查是否小于等于1
//   var hitPoint = 0;
//   print(hitPoint <= 0);
//   assert(hitPoint <= 0);
//  检查是否为null
  var unicorn;
  assert(unicorn == null);
  print(unicorn == null);
//检查是否为NaN
//   var iMean = 0 / 0;
//   assert(iMean.isNaN);
//   print(iMean.isNaN);
  String s = "1,3,3,d";
  // List<String> arr = s.split(',');
  // print(arr);
//  查找并替换
  String g = s.splitMapJoin(",",
      onMatch: (Match match) {
    // 用匹配的值替换
    return "19";
  }, onNonMatch: (String nonMatch) {
    // 用不匹配的值替换
    return "a";
  });

  print(g);
  String i = "stringing";
  String ii=i.replaceAllMapped("i",(Match match){
      return "小妮";
  });
  print(ii);

}
